package ldh.im.fxbase.richtext;

import javafx.geometry.Point2D;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.input.KeyCode;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Path;
import javafx.scene.shape.PathElement;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.HitInfo;
import javafx.scene.text.Text;
import javafx.scene.text.TextAlignment;

public class ImText extends StackPane {

    private Text text;

    private Path selectPath = new Path();

    private Rectangle clickPoint = new Rectangle();
    private int start = 0, end = 0;

    public ImText(TextAlignment textAlignment) {
        this.getStyleClass().add("im-text-pane");
        text = new Text();
        text.setSelectionFill(Color.WHITE);
        text.setLineSpacing(0);
        text.getStyleClass().add("im-text");

        if (textAlignment != null) {
            text.setTextAlignment(textAlignment);
            if (textAlignment == TextAlignment.RIGHT) {
                this.setAlignment(Pos.CENTER_RIGHT);
            } else {
                this.setAlignment(Pos.CENTER_LEFT);
            }
        }

        Group group = new Group();
        group.getChildren().addAll(selectPath, text);
        this.getChildren().addAll(group);

        bindEvent();
    }

    public void setImContent(String content) {
        text.setText(content);
    }

    private void bindEvent() {
        text.setOnMousePressed(e -> {
            clickPoint.setX(e.getX());
            clickPoint.setY(e.getY());
            ImText.this.requestFocus();

            if (e.isPrimaryButtonDown()) {
                clearSelect();
            }
        });

        text.setOnMouseDragged(e -> {
            select(e);
        });

        text.setOnMouseDragExited(e->{
            if(start != end && end == text.getText().length() -1) {
                end = text.getText().length();
                selectText(start, end);
            }
        });

        this.setOnKeyPressed(e->{
            if(e.isControlDown() && e.getCode() == KeyCode.C) {
                copy();
            }
        });
        text.setOnKeyPressed(e->{
            if(e.isControlDown() && e.getCode() == KeyCode.C) {
                copy();
            }
        });

        this.setOnMouseClicked(e->{
            if(e.getClickCount() == 2) {
                selectAll();
            }
        });

        text.focusedProperty().addListener(e->{
            if (!text.focusedProperty().get() && !ImText.this.focusedProperty().get()) {
                clearSelect();
            }
        });
    }

    private void selectAll() {
        start = 0;
        end = text.getText().length();
        if (start == end) return;
        selectText(start, end);
    }

    private void select(MouseEvent e) {
        HitInfo characterHit = text.hitTest(new Point2D(e.getX(), e.getY()));

        HitInfo startHit = text.hitTest(new Point2D(clickPoint.getX(), clickPoint.getY()));
        int start1 = startHit.getCharIndex();

        int end1 = characterHit.getCharIndex();

        if (start1 > end1) {
            int t = end1;
            end1 = start1+1;
            start1 = t;
        } else {
            end1++;
        }
        start = start1;
        end = end1;

        selectText(start, end);
    }

    private void selectText(int start, int end) {
        text.setSelectionStart(start);
        text.setSelectionEnd(end);
        text.setSelectionFill(Color.WHITE);

        PathElement[] pes = text.getSelectionShape();

        selectPath.setStroke(null);
        selectPath.setFill(Color.BLUEVIOLET);
        selectPath.getElements().clear();
        selectPath.getElements().addAll(pes);

        text.requestFocus();
    }

    public Text getText() {
        return text;
    }

    private void copy() {
        if (!(start >= 0 && end > 0)) return;
        Clipboard clipboard = Clipboard.getSystemClipboard();
        ClipboardContent content = new ClipboardContent();
        content.putString(text.getText().substring(start, end) );

        clipboard.setContent(content);
    }

    private void clearSelect() {
        selectPath.getElements().clear();
        start = 0;
        end = 0;
        text.setSelectionFill(Color.BLACK);
    }
}
